package com.starhub.common.security.config;

import com.starhub.api.sys.user.service.impl.UserDetailsServiceImpl;
import com.starhub.common.security.filter.JwtAuthenticationTokenFilter;
import com.starhub.common.security.filter.ValidateCodeFilter;
import com.starhub.common.security.handle.AccessDeniedHandlerImpl;
import com.starhub.common.security.handle.AuthenticationEntryPointImpl;
import com.starhub.common.security.handle.LogoutSuccessHandlerImpl;
import com.starhub.common.security.util.JWTUtils;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

import java.util.Arrays;


/**
 * spring security配置
 */
@Configuration
@AllArgsConstructor
@EnableWebSecurity // 是开启SpringSecurity的默认行为
@EnableMethodSecurity // 开启方法级别的权限注解，Security6新增
public class SecurityConfig {

    /**
     * 自定义用户认证逻辑
     */
    @Autowired
    public UserDetailsServiceImpl userDetailsServiceImpl;
    /**
     *  验证码验证逻辑过滤器
     */
    @Autowired
    public ValidateCodeFilter validateCodeFilter;

    /**
     * 认证失败处理类(jwt)与web用其一
     */
    @Autowired
    private AuthenticationEntryPointImpl unauthorizedHandler;


    /**
     * 退出处理类
     */
    @Autowired
    private LogoutSuccessHandlerImpl logoutSuccessHandler;

    /**
     * token认证过滤器
     */
    @Autowired
    private JwtAuthenticationTokenFilter authenticationTokenFilter;


    /**
     * 获取AuthenticationManager（认证管理器），登录时认证使用
     * 默认AuthenticationManager使用的事暴露出来的UserDetailsService和PasswordEncoder)
     * @return
     * @throws Exception
     */
    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        DaoAuthenticationProvider provider =  new DaoAuthenticationProvider();
        provider.setPasswordEncoder(bCryptPasswordEncoder());
        provider.setUserDetailsService(userDetailsServiceImpl);
        return new ProviderManager(provider);
    }


    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                // 禁用 CSRF 和 Session
                .csrf(AbstractHttpConfigurer::disable)
                // 会话管理
                .sessionManagement(session ->
                        session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                // 授权配置
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers(JWTUtils.WHITELIST).permitAll()
                        .anyRequest().authenticated()
                )
                // 异常处理
                .exceptionHandling(exceptions ->
                        exceptions
                                .authenticationEntryPoint(unauthorizedHandler)
                                .accessDeniedHandler(new AccessDeniedHandlerImpl()))

                // 过滤器配置
                .addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
                .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }


    /**
     * 强散列哈希加密实现
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }


    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().requestMatchers("/css/**","/js/**","/img/**","/uploads/**","*/favicon.ico","*/vite.svg"); //新配置

    }


    /**
     * 跨域配置
     */
    @Bean
    public UrlBasedCorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(Arrays.asList(
                "http://localhost:3000",  // 前端开发环境
                "https://production-domain.com" // 生产环境域名
        ));
        config.setAllowedMethods(Arrays.asList(
                HttpMethod.GET.name(),
                HttpMethod.POST.name(),
                HttpMethod.PUT.name(),
                HttpMethod.DELETE.name()
        ));
        config.setAllowedHeaders(Arrays.asList("*"));
        config.setExposedHeaders(Arrays.asList(
                "Authorization",
                "X-Captcha-Token"
        ));
        config.setMaxAge(3600L);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
    }


    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
